package restless.core.audio {
	
	import com.greensock.TweenLite;
	import flash.events.Event;
	import restless.core.audio.soundtouch.SimpleFilter;
	import restless.core.audio.soundtouch.SoundTouch;
	import restless.core.gameObjs.RLEUpdateRenderObj;
	import restless.core.managers.RLESoundManager;
	
	import restless.core.interfaces.IUR;
	import restless.core.interfaces.IDispose;
	
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.utils.getQualifiedClassName;
	import flash.events.SampleDataEvent;
	
	/**
 	 * @author	Matt Przybylski [http://www.reintroducing.com]
		 * 		Jordan Laine www.mustnotsleepgames.com
 	 * @version 1.5 rle
 	 */
	
	public class RLESoundItem extends RLEUpdateRenderObj implements IDispose {
		protected var soundM:RLESoundManager;
		
		private var _fadeTween:TweenLite;
		private var soundTouch:SoundTouch;
		private var soundFilter:SimpleFilter;
		
		protected var sndSource:Sound;
		protected var sndMod:Sound;
		protected var tempSound:Sound;
		
		protected var channel:SoundChannel;
		protected var nVolume:Number;
		
		protected var nPreviousVolume:Number;
		private var bMod:Boolean;
		private var bMuted:Boolean = false;
		private var nLoopsLeft:int;
		
		public var nStart:Number;
		public var nPosition:int;
		public var nLoops:int;
		public var bPlaying:Boolean = false;
		public var bRepeat:Boolean;
		public var bPause:Boolean;
		public var bBeat:Boolean;
		public var nBeatDelay:int;
		public var nLength:Number;
		private var nBeatCount:int;
		
		public function RLESoundItem():void {
			setRE();
			soundM = RE.soundM;
			init();
		}
		
		private function init():void {
			channel = soundM.getChannel();
		}
		
		private function fadeComplete(stopOnComplete:Boolean):void {
			if (stopOnComplete) { stop(); }
			//fadeTween = null;
		}
		
		public function play(startTime:Number = 0, loops:int = 0, resumeTween:Boolean = true):void {	
			if (bPause) { return; }
			if (bMuted) { return; }	
			if (bPlaying) {
				channel.stop();
			}
			nStart = startTime;
			nLoops = loops;
			nLoopsLeft = nLoops;
			bPause = false;
			bPlaying = true;
			tempSound = getSound();
			nLength = tempSound.length;
			channel = tempSound.play(nStart, 0, new SoundTransform(volume));
			if (nLoops > 0) {
				channel.addEventListener(Event.SOUND_COMPLETE, soundComplete);
			}
		}
		
		protected function soundComplete(e:Event):void {
			if (nLoopsLeft > 0) {
				tempSound = getSound();
				channel.removeEventListener(Event.SOUND_COMPLETE, soundComplete);
				channel = tempSound.play(nStart, 0, new SoundTransform(volume));
				channel.addEventListener(Event.SOUND_COMPLETE, soundComplete);
			} else {
				stop();
			}
			nLoopsLeft--;
		}
		
		public function beat():void {
			if (bPause) { return; }
			
			nBeatCount++;
			if (nBeatDelay < nBeatCount) { return; }
			nBeatCount = 0;
			
			channel = getSound(false).play(nPosition, nLoops, new SoundTransform(volume));
			bPause = false;
			bPlaying = true;
		}
		
		public function pause(pauseTween:Boolean = true):void {
			bPause = !bPause;
			if (bPause) {
				
				if ( pauseTween && fadeTween._active ) {
					 fadeTween.pause(); 
				} else {
					nPosition = channel.position;
					channel.stop();
				}
			} else {
				if ( pauseTween && fadeTween._active ) {
					fadeTween.resume(); 
				} else {
					channel = getSound().play(nPosition, nLoopsLeft, new SoundTransform(volume));
				}
			}	
		}
		
		public function stop():void {
			if (!bPlaying) { return; }
			channel.stop();
			bPlaying = false;
			channel.removeEventListener(Event.SOUND_COMPLETE, soundComplete);
			fadeTween = null;
		}
		
		public function fade(volume:Number = 0, fadeLength:Number = 1, stopOnComplete:Boolean = false):void {
			fadeTween = TweenLite.to(channel, fadeLength, {volume: volume, onComplete: fadeComplete, onCompleteParams: [stopOnComplete]});
		}
		
		public function set volume(volume:Number):void {
			if (bMuted) { return; }	
			nPreviousVolume = nVolume;
			nVolume = volume;
			channel.soundTransform.volume = nVolume;
		}
		
		public function get volume():Number {
		    return nVolume;
		}
		
		public function set loop(num:int):void {
			nLoops = num;
		}
		
		public function get loops():int {
			return nLoops;
		}
		
		public function set mute(bool:Boolean):void {
			if (bMuted == bool) { return; }
			
			bMuted = bool;
			
			if (bMuted) {
				volume = 0;	
			} else {
				volume = nPreviousVolume;
			}
			
		}
		
		public function get mute():Boolean {
			return bMuted;
		}
		
		public function mod(pitch:Number = 1, rate:Number = 1, tempo:Number = 1 ):void {
			bMod = true;
			if (sndMod == null) { sndMod = new Sound(); }
			if (soundTouch == null) {
				soundTouch = new SoundTouch();
			} else {
				//might cause problems
				soundTouch.clear();
			}
			
			soundTouch.rate = rate;
			soundTouch.tempo = tempo;
			soundTouch.pitch = pitch;
			
			soundFilter = new SimpleFilter(sndSource, soundTouch);
			sndMod.addEventListener(SampleDataEvent.SAMPLE_DATA, soundFilter.handleSampleData);
		}
		
		public function removeMod():void {
			if (bMod) {
				sndMod.removeEventListener(SampleDataEvent.SAMPLE_DATA, soundFilter.handleSampleData);
				bMod = false;
			}
		}
		
		public function get fadeTween():TweenLite {
		    return _fadeTween;
		}
		
		public function set fadeTween(num:TweenLite):void {
			if (num == null) { TweenLite.killTweensOf(this); }
			
			_fadeTween = num;
		}
		
		public function setSound(sound:Sound):void {
			sndSource = sound;
		}
		
		public function getSound(source:Boolean = false):Sound {
			if (bMod && !source) { return sndMod; }	
			else { return sndSource; }
		}
		
		override public function dispose():void {
			if (bMod) {
				sndMod.removeEventListener(SampleDataEvent.SAMPLE_DATA, soundFilter.handleSampleData);
			}
			channel.stop();
			soundTouch = null;
			soundFilter = null;
			channel = null;
			fadeTween = null;
			super.dispose();
		}
	}
}